import {
  createText,
  setText,
  createComment,
  unmount,
  insert,
} from "../utils/browserDOMAPI.js";

import { mountElement, patchElement, patchChildren } from "./element.js";

import { mountComponent, patchComponent } from "./component.js";

export const Types = {
  TEXT: Symbol("TEXT"),
  COMMENT: Symbol("COMMENT"),
  FRAGEMENT: Symbol("FRAGMENT"),
};

/**
 * @description 挂载、更新虚拟节点
 * @param {*} oldVnode 旧虚拟节点
 * @param {*} vnode 新虚拟节点
 * @param {*} container 挂载容器
 */
export function patch(oldVnode, vnode, container, anchor) {
  /* 如果非第一次挂载，并且新旧vnode的内容不一样（即元素不一样） */
  if (oldVnode && oldVnode.type !== vnode.type) {
    unmount(oldVnode);
    oldVnode = null;
  }

  const { type } = vnode;

  /* 代码能运行到这的话，表示旧vnode和新vnode的内容（元素）是一样的 */
  /* 如果类型是字符串，代表是 element 元素 */
  if (typeof type === "string") {
    /* 如果旧的 vnode 不存在，表示第一次挂载，则调用 mountElement 函数完成真实dom节点挂载 */
    if (!oldVnode) {
      /* 第一次挂载 */
      mountElement(vnode, container, anchor);
    } else {
      /* 旧的vnode存在即表示更新 */
      patchElement(oldVnode, vnode);
    }
  } else if (type === Types.TEXT) {
    if (!oldVnode) {
      /* 第一次挂载，创建文本节点 */
      const el = (vnode.el = createText(vnode.children));
      /* 将文本节点添加到容器中 */
      insert(el, container);
    } else {
      /* 获取到节点 */
      const el = (vnode.el = oldVnode.el);
      /* 新旧内容不一致，替换内容 */
      if (vnode.children !== oldVnode.children) {
        setText(el, vnode.children);
      }
    }
  } else if (type === Types.COMMENT) {
    /* 注释节点 */

    if (!oldVnode) {
      /* 第一次挂载 */
      const el = (vnode.el = createComment(vnode.children));
      /* 将注释节点添加到容器中 */
      insert(el, container);
    } else {
      /* 获取到节点 */
      const el = (vnode.el = oldVnode.el);
      /* 新旧内容不一致，替换内容 */
      if (vnode.children !== oldVnode.children) {
        setText(el, vnode.children);
      }
    }
  } else if (type === Types.FRAGEMENT) {
    /* 片段 */

    if (!oldVnode) {
      vnode.children.forEach((child) => patch(null, child, container));
    } else {
      patchChildren(oldVnode, vnode, container);
    }
  } else if (typeof type === "object" || typeof type === "function") {
    /* vnode的type是一个对象，描述的是一个组件 */
    console.log("vnode是一个组件");

    /* 组件时第一次挂载的情况下，挂载组件 */
    if (!oldVnode) {
      mountComponent(vnode, container, anchor);
    } else {
      /* 组件非第一次挂载的情况下，更新组件 */
      patchComponent(oldVnode, vnode, anchor);
    }
  }
}

/**
 * @description 创建渲染器
 * @param {*} vnode 虚拟节点
 * @param {*} container 挂载容器
 * @returns
 */
function createRenderer() {
  /**
   * @description 渲染函数
   * @param {*} vnode 虚拟节点
   * @param {*} container 挂载容器
   */
  function render(vnode, container) {
    /* 传了新的虚拟节点 */
    if (vnode) {
      /* 挂载或更新真实节点，挂载：container._vnode 为 undefined，更新：container._vnode 为 上一次渲染的 vnode */
      patch(container._vnode, vnode, container);
    } else {
      /* 旧的vnode存在并且没有传新的vnode，说明是卸载操作 */
      if (container._vnode) {
        unmount(container._vnode);
      }
    }

    /* 把vnode存储到 container._vnode下，即后续渲染中的旧 vnode */
    container._vnode = vnode;
  }

  return {
    render,
  };
}

export const renderer = createRenderer();
